/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */
/*
 * Created on Jun 12, 2004
 *
 */
package edu.mit.csail.relo.parts;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.functors.InstanceofPredicate;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.SWTGraphics;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.WorkbenchPart;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.rio.RdfDocumentWriter;
import org.openrdf.sesame.sail.StatementIterator;
import org.openrdf.vocabulary.RDF;

import edu.mit.csail.relo.ReloCore;
import edu.mit.csail.relo.ReloPlugin;
import edu.mit.csail.relo.agent.BrowseModel;
import edu.mit.csail.relo.agent.ScriptManager;
import edu.mit.csail.relo.eclipse.gef.IncrementalGraphicalEditPart;
import edu.mit.csail.relo.graph.GraphAnimation;
import edu.mit.csail.relo.graph.GraphLayoutManager;
import edu.mit.csail.relo.modelBridge.Artifact;
import edu.mit.csail.relo.modelBridge.ArtifactRel;
import edu.mit.csail.relo.modelBridge.DerivedArtifact;
import edu.mit.csail.relo.modelBridge.ReloDoc;
import edu.mit.csail.relo.modelBridge.ReloDoc.DocPath;
import edu.mit.csail.relo.parts.NavAidsEditPolicy.BasicRootController;
import edu.mit.csail.relo.parts.NavAidsEditPolicy.NavAidsEditPart;
import edu.mit.csail.relo.store.ReloRdfRepository;
import edu.mit.csail.relo.store.StoreUnionRepository;
import edu.mit.csail.relo.store.StoreUtil;
import edu.mit.csail.relo.ui.ReloEditor;
import edu.mit.csail.relo.ui.ReloView;
import edu.mit.csail.relo.ui.GraphicalView.ViewEditDomain;
import edu.mit.csail.relo.utils.LoadUtils;

/**
 * @author vineet
 *
 */
public class ReloController extends AbstractReloEditPart implements BasicRootController {
    
	static final Logger logger = ReloPlugin.getLogger(ReloController.class);

	public BrowseModel bm = null;
	
    public ReloController() {
        //ConsoleView.setVariable("rc", this);
    }
    
    @Override
    public BrowseModel getBrowseModel() {
        return bm;
    }

    @Override
    public void setParent(EditPart parent) {
    	super.setParent(parent);
    	
        EditDomain editDomain = getRoot().getViewer().getEditDomain();
        if (editDomain instanceof DefaultEditDomain) {
            ReloEditor editor = (ReloEditor) ((DefaultEditDomain)editDomain).getEditorPart();
            bm = editor.bm;
        } else if (editDomain instanceof ViewEditDomain) {
            ReloView view = (ReloView) ((ViewEditDomain)editDomain).getViewPart();
            bm = view.bm;
        } else {
        	logger.error("Unable to understand EditDomain - type: " + editDomain.getClass(), new Exception());
        }
    }

	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
	 */
	@Override
    protected IFigure createFigure() {
		Figure f = new FreeformLayer() {
			@Override
            public String toString() {
				return "{ReloController.createFigure()->Figure}";
			}
		};
		f.setOpaque(true);
		f.setLayoutManager(new GraphLayoutManager(this, getRoot(), ScriptManager.selection));

		return f;
	}
    
    public void performUndoableLayout() {
        IFigure f = this.getFigure();
        GraphLayoutManager glm = (GraphLayoutManager) f.getLayoutManager();
        glm.undoableLayout();
    }
    public GraphLayoutManager getLayoutMgr() {
        return (GraphLayoutManager) this.getFigure().getLayoutManager();
    }
    public Command getLayoutCmd() {
        return getLayoutMgr().getLayoutCmd();
    }
    public Command getRemoveAllCmd() {
    	List<EditPart> eps = getChildrenAsTypedList();
    	CompoundCommand cc = new CompoundCommand();
    	for (EditPart part : eps) {
			Command currCmd = part.getCommand(new Request(RequestConstants.REQ_DELETE));
			if (currCmd != null) {
				cc.add(currCmd);
			}
		}
    	return cc.unwrap();
    }


    //TODO: compare with below, and ensure that this can be deleted
	//private void addFocusArtifact(Artifact art) {
	//	if (!isArtifactVisible(art)) {
	//	    appendModelChild(art);
	//		ArtifactEditPart aep = (ArtifactEditPart) createChild(art);
	//		aep.currSL = ArtifactEditPart.focusedSL;
	//		addChild(aep, -1);
	//	}
	//}

    private void addFocusArtifacts(ReloRdfRepository docRepo, Map<Resource,ArtifactEditPart> viewRes2ArtifactEPMap) {
		//addFocusArtifacts(doc.getItems(), doc.getItemsPositions());
	    //rdfWriter.writeStatement(viewRes, StoreUtil.createMemURI(RDF.TYPE), ReloCore.node);	
		StatementIterator si = docRepo.getStatements(null, docRepo.rdfType, ReloCore.node);
        while (si.hasNext()) {
            Resource viewRes = si.next().getSubject();

            ArtifactEditPart aep = ArtifactEditPart.readRDF(this, docRepo, viewRes);
            viewRes2ArtifactEPMap.put(viewRes, aep);
        }
        si.close();
    }
    
    private void addLinks(ReloRdfRepository docRepo, Map<Resource,ArtifactEditPart> viewRes2ArtifactEPMap) {
        StatementIterator si = docRepo.getStatements(null, docRepo.rdfType, ReloCore.link);
		while (si.hasNext()) {
			Resource viewRes = si.next().getSubject();

            /*ArtifactRelEditPart arep = */ArtifactRelEditPart.readRDF(this, docRepo, viewRes2ArtifactEPMap, viewRes);
            //viewRes2ArtifactEPMap.put(viewRes, arep);
		}
		si.close();
    }
    
    /**
     * Returns the editor part for this controller
     * 
     */
    public ReloEditor getReloEditor() {
        EditDomain editDomain = getRoot().getViewer().getEditDomain();
        if (editDomain instanceof DefaultEditDomain) {
            return (ReloEditor) ((DefaultEditDomain)editDomain).getEditorPart();
        } else {
        	// caller needs to support when we are not opening in an editor
        	return null;
        }
    }
    public WorkbenchPart getWorkbenchPart() {
        EditDomain editDomain = getRoot().getViewer().getEditDomain();
        if (editDomain instanceof DefaultEditDomain) {
            return (ReloEditor) ((DefaultEditDomain)editDomain).getEditorPart();
        } else if (editDomain instanceof ViewEditDomain) {
            return (ReloView) ((ViewEditDomain)editDomain).getViewPart();
        } else {
        	logger.error("Unable to understand EditDomain - type: " + editDomain.getClass(), new Exception());
        	return null;
        }
    }
    
    /**
     * Returns the file for the editor part of this controller
     * 
     */
    public IResource getReloEditorResource() {
    	ReloEditor editor = getReloEditor();
    	if (editor == null) return null;
    	
		IEditorInput input = editor.getEditorInput();
    	if(input instanceof FileEditorInput) {
    		return ((FileEditorInput)input).getFile();
    	}
    	return null;
    }
    
    private void addFocusArtifacts(List items, final Map itemsPositions) {
	    CollectionUtils.forAllDo(items, new Closure() {
            public void execute(Object item) {
                Artifact art = null;
                if (item instanceof Artifact)
                    art = (Artifact) item;
                else if (item instanceof DocPath)
                    art = bm.getArtifact( ((DocPath) item).src );
		        else 
		            art = bm.getArtifact(item);
		        
		        if (art == null) return;
		        
                //logger.info("Creating aep: " + art);
            	ArtifactEditPart aep  = createOrFindArtifactEditPart(art, ArtifactEditPart.focusedSL);
           	
            	// is position stored?
            	if (itemsPositions.containsKey(item))
            	    aep.getFigure().setLocation((Point) itemsPositions.get(item));
                
                // is relationship stored?
                if (item instanceof DocPath) {
                    DocPath path = (DocPath) item;
                    Artifact dstArt = bm.getArtifact( path.dst );
                    ArtifactEditPart dstAEP  = createOrFindArtifactEditPart(dstArt, ArtifactEditPart.focusedSL);
                    if (dstAEP != null)
                        ReloController.this.addRel(aep, path.rel, dstAEP);
                }
            }});
        performUndoableLayout();
	}


    public void hideRel(AbstractReloRelationPart relEP) {
        ArtifactRel rel = (ArtifactRel) relEP.getModel();

        ArtifactEditPart srcAEP = (ArtifactEditPart) relEP.getSource();
        if (srcAEP != null && srcAEP.isActive()) srcAEP.removeModelSourceConnections(rel);

        ArtifactEditPart dstAEP = (ArtifactEditPart) relEP.getTarget();
        if (dstAEP != null && dstAEP.isActive()) dstAEP.removeModelTargetConnections(rel);

        logger.debug(rel.tag + " Hiding " + rel.getType() + ": " + rel.toString());
    }
    public void hideRel(CompoundCommand tgtCmd, AbstractReloRelationPart relEP) {
        final ArtifactRel rel = (ArtifactRel) relEP.getModel();
        final ArtifactEditPart srcAEP = (ArtifactEditPart) relEP.getSource();
        final ArtifactEditPart dstAEP = (ArtifactEditPart) relEP.getTarget();

        tgtCmd.add(new Command("Hide Relationship") {
            @Override
            public void execute() { 
                logger.debug(rel.tag + " Hiding " + rel.getType() + ": " + rel.toString());
                if (srcAEP != null && srcAEP.isActive()) srcAEP.removeModelSourceConnections(rel);
                if (dstAEP != null && dstAEP.isActive()) dstAEP.removeModelTargetConnections(rel);
            }
            @Override
            public void undo() {
                addRel(srcAEP, rel, dstAEP);
            }
        });

    }
    // TODO: analyze below for removal - seems to be part of the old approach:
	// if src/dst doesn't exist flag error
	//private ArtifactRelEditPart addRel(Artifact srcArt, ArtifactRel artRel, Artifact dstArt) {
	//    ArtifactEditPart srcAEP = createOrFindInferredArtifactEditPart(srcArt);
	//    ArtifactEditPart dstAEP = createOrFindInferredArtifactEditPart(dstArt);
	//    
	//    // if either could not be found/created
	//    if (srcAEP == null || dstAEP == null) {
	//        logger.error("Source/Destination==null", new IllegalArgumentException());
	//        return null;
	//    }
	//    
	//    return addRel(srcAEP, artRel, dstAEP);
	//}
    
    public void addRel(CompoundCommand tgtCmd, ArtifactEditPart srcAEP, URI relationRes, ArtifactEditPart dstAEP) {
        ArtifactRel rel = new ArtifactRel(srcAEP, dstAEP, relationRes);
        addRel(tgtCmd, srcAEP, rel, dstAEP);
    }
    
    public void addRel(CompoundCommand tgtCmd, final ArtifactEditPart srcAEP, final ArtifactRel rel, final ArtifactEditPart dstAEP) {
        if (srcAEP.findEditPart(rel) != null) {
            // rel has already been added
            return;
        }
        
        tgtCmd.add(new Command("Add Relationship") {
            AbstractReloRelationPart relPart = null;
            @Override
            public void execute() { 
                //logger.debug(rel.tag + " Creating " + rel.relationRes + ": " + rel.toString());
                relPart = (AbstractReloRelationPart) srcAEP.findConnection(rel);
                if (relPart != null) return;

                relPart = (AbstractReloRelationPart) srcAEP.addModelSourceConnections(rel);
                dstAEP.addModelTargetConnections(rel, relPart);
            }
            @Override
            public void undo() { 
                //logger.debug(rel.tag + " Removing " + rel.relationRes + ": " + rel.toString());
                srcAEP.getRootController().hideRel(relPart);
            }
        });
    }
    public ArtifactRelEditPart addRel(ArtifactEditPart srcAEP, URI relationRes, ArtifactEditPart dstAEP) {
        ArtifactRel rel = new ArtifactRel(srcAEP, dstAEP, relationRes);
        return addRel(srcAEP, rel, dstAEP);
    }
    public ArtifactRelEditPart addRel(ArtifactEditPart srcAEP, ArtifactRel rel, ArtifactEditPart dstAEP) {
    	ArtifactRelEditPart relEP = (ArtifactRelEditPart) srcAEP.addModelSourceConnections(rel);
        dstAEP.addModelTargetConnections(rel, relEP);
        //logger.debug(rel.tag + " Creating " + rel.relationRes + ": " + rel.toString());
        return relEP;
    }
	public ArtifactRelEditPart addRel(Artifact srcArt, URI relationRes, Artifact dstArt) {
		ArtifactEditPart srcAEP = createOrFindInferredArtifactEditPart(srcArt);
		ArtifactEditPart dstAEP = createOrFindInferredArtifactEditPart(dstArt);
		return addRel(srcAEP, relationRes, dstAEP);
	}
    public void reConnectRel(ArtifactEditPart newSrcAEP, ArtifactRelEditPart relEP, ArtifactEditPart newDstAEP) {
        ArtifactEditPart oldSrcAEP = (ArtifactEditPart) relEP.getSource();
        ArtifactEditPart oldDstAEP = (ArtifactEditPart) relEP.getTarget();
        if (newSrcAEP != oldSrcAEP) {
            oldSrcAEP.removeModelSourceConnections(relEP.getModel(), relEP);
            newSrcAEP.addModelSourceConnections(relEP.getModel(), relEP);
        }
        if (newDstAEP != oldDstAEP) {
            oldDstAEP.removeModelTargetConnections(relEP.getModel(), relEP);
            newDstAEP.addModelTargetConnections(relEP.getModel(), relEP);
        }
        //ArtifactRel rel = relEP.getArtifactRel();
        //logger.debug(rel.tag + " Creating " + rel.relationRes + ": " + rel.toString());
    }

    /**
     * Inferred items should be first checked against this
     */
    private Set<Artifact> removedArtifacts = new HashSet<Artifact>(100);
	
    public ArtifactEditPart findArtifactEditPart(Artifact art) {
        return (ArtifactEditPart) findEditPart(art);
    }
	public ArtifactEditPart createOrFindQueriedArtifactEditPart(Resource res) {
        return createOrFindQueriedArtifactEditPart(new Artifact(res));
    }
	public ArtifactEditPart createOrFindQueriedArtifactEditPart(Artifact art) {
        return createOrFindArtifactEditPart(art, ArtifactEditPart.queriedSL);
    }
	public ArtifactEditPart createOrFindInferredArtifactEditPart(Resource res) {
        return createOrFindInferredArtifactEditPart(new Artifact(res));
    }
	public ArtifactEditPart createOrFindInferredArtifactEditPart(Artifact art) {
        return createOrFindArtifactEditPart(art, ArtifactEditPart.inferredSL);
    }
	public ArtifactEditPart createOrFindArtifactEditPart(Artifact cu, final int createSL) {
        if (createSL <= ArtifactEditPart.inferredSL && !artInferCreatable(cu)) {
            return null;
        }
		return createOrFindArtifactEditPart(cu, new Closure() {
            public void execute(Object ep) {
                ((ArtifactEditPart)ep).incrSelectionLevel(createSL);
            }});
    }
    
	public ArtifactEditPart createOrFindArtifactEditPart(Artifact art, Closure createClosure) {
        ArtifactEditPart aep = (ArtifactEditPart) findEditPart(art);
        if (aep != null) {
            if (createClosure != null) createClosure.execute(aep);
            return aep;
        }

        //log("createOrFindCodeUnitEditPart creating: " + cu);
        //logger.debug("Creating EditPart: " + art.elementRes);
        return createArtifactEditPart(art, createClosure);
    }

    
    /**
     * Note: This method only places art with the right parent, it does *not*
     * check if art has any valid children to be place inside it,for which just
     * call ArtifactEditPart.assertParenthood (which can take time to go through
     * all the children, which is why it is not checked by default)
     * 
     * @param art
     * @param epInit
     * @return
     */
    public ArtifactEditPart createArtifactEditPart(Artifact art, Closure epInit) {
        // check if any parent is visible (and add art as a child to that parent) 
        Artifact parentArt = art;
        AbstractReloEditPart parentEP = null;
        do {
            parentArt = parentArt.getParentArtifact(getBrowseModel().getRepo());
            parentEP = (AbstractReloEditPart) findEditPart(parentArt);
        } while (parentArt != null && parentEP == null);
        // either: parentArt==null or parentEP!=null

        if (parentArt == null)  // add to top level 
            parentEP = this;
        // now: parentEP!=null
        
        return (ArtifactEditPart) parentEP.appendModelAndChild(art, epInit);
    }
    
    /**
     * Checks with the browse model is the artifact is creatable
     * @param art
     * @return
     */
    public boolean artCreatable(Artifact art) {
    	if (!getRepo().hasStatement(art.elementRes, getRepo().rdfType, null)) return false;
        Resource artType = art.getType(getRepo());
        if (!bm.artifactLoadable(art, artType)) return false;
        return true;
    }
    
    /**
     * Checks with the browse model is the artifact is creatable
     * @param art
     * @return
     */
    public boolean artInferCreatable(Artifact art) {
        if (!artCreatable(art)) return false;
        if (removedArtifacts.contains(art)) return false;
        return true;
    }
    public void addNode(ArtifactEditPart nodeAEP, IncrementalGraphicalEditPart parentIGEP) {
        removedArtifacts.remove(nodeAEP.getArtifact());
        parentIGEP.addModelAndChild(nodeAEP);
    }
    public void removeNode(ArtifactEditPart nodeAEP) {
        removedArtifacts.add(nodeAEP.getArtifact());
        ((IncrementalGraphicalEditPart) nodeAEP.getParent()).removeModelAndChild(nodeAEP);
    }
    
    public List<ArtifactEditPart> getSelectedArtifactEditParts() {
    	List<ArtifactEditPart> allParts = getVisibleArtifactEditParts();
		List<ArtifactEditPart> selectedParts = new ArrayList<ArtifactEditPart>();		
		for(ArtifactEditPart part : allParts) {
			if(part.getSelected()!=EditPart.SELECTED_NONE) {
				selectedParts.add(part);
			}
		}    
		return selectedParts;
    }
    
    @SuppressWarnings("unchecked")
    public List<ArtifactRelEditPart> getVisibleArtifactRelEditParts() {
	    List allChildren = new LinkedList (getViewer().getEditPartRegistry().values());
        CollectionUtils.filter(allChildren, new InstanceofPredicate(ArtifactRelEditPart.class));
        return allChildren;
	}
    
	@SuppressWarnings("unchecked")
    public List<ArtifactEditPart> getVisibleArtifactEditParts() {
	    List allChildren = new LinkedList (getViewer().getEditPartRegistry().values());
        CollectionUtils.filter(allChildren, new InstanceofPredicate(ArtifactEditPart.class));
        return allChildren;
	}

	// Note: this method return's CodeUnitEditPart's
	public List<ArtifactEditPart> getVisibleNonDerivedArtifactEditParts() {
	    List<ArtifactEditPart> visAEPs = getVisibleArtifactEditParts();
        CollectionUtils.filter(visAEPs, new Predicate() {
            public boolean evaluate(Object elem) {
                if (((EditPart) elem).getModel() instanceof DerivedArtifact) {
                    return false;
                }
                return true;
            }});
        return visAEPs;
	}

	public ReloRdfRepository getAllJenaRelatioships() {
		List<ArtifactEditPart> lst = getVisibleNonDerivedArtifactEditParts();
		ReloRdfRepository retVal = StoreUtil.getMemRepository();
		retVal.startTransaction();
        for (ArtifactEditPart aep : lst) {
            for (ConnectionEditPart connEP : aep.getSourceConnectionsAsEP()) {
                ArtifactRel ar = (ArtifactRel) connEP.getModel();
                retVal.addStatement(ar.getSrc().elementRes, ar.getType(), ar.getDest().elementRes);
            }
		}
		retVal.commitTransaction();
		return retVal;
	}

	
	public boolean isArtifactFocused(Artifact art) {
	    ArtifactEditPart aep = (ArtifactEditPart) findEditPart(art);
	    if (aep == null) {
	        return false;
	    }
	    return aep.isModelFocused();
	}

	public void removeTopLevelCU(Artifact art) {
	    removeModelChild(art);
	}


	/**
	 * @see org.eclipse.gef.editparts.AbstractEditPart#isSelectable()
	 */
	@Override
    public boolean isSelectable() {
		return false;
	}

	CommandStackListener animationStackListener = new CommandStackListener() {
		public void commandStackChanged(EventObject event) {
			if (!GraphAnimation.captureLayout(getFigure()))
				return;
			while (GraphAnimation.step())
				getFigure().getUpdateManager().performUpdate();
			GraphAnimation.end();
		}
	};

	/**
	 * @see org.eclipse.gef.examples.flow.parts.ActivityPart#activate()
	 */
	@Override
    public void activate() {
		try {
			super.activate();
			getViewer().getEditDomain().getCommandStack().addCommandStackListener(animationStackListener);
			//logger.info("Loading: " + ((ReloDoc) getModel()).getItems());

			execute(new Command("Load document (" + ((ReloDoc) getModel()).getItems().size() + " items)") {
				@Override
                public void execute() {
					((StoreUnionRepository)getBrowseModel().getRepo()).setCacheRepo(StoreUtil.getMemRepository());
					// connect to the model and so set the focusCU
					ReloDoc doc = (ReloDoc) getModel();
					if (doc.getItems().size() > 0) {
					    addFocusArtifacts(doc.getItems(), Collections.EMPTY_MAP);
					}
					if (doc.getRDFDoc() != null) {
						IResource editorResource = getReloEditorResource();
						LoadUtils.removeErrors(editorResource);
                        Map<Resource,ArtifactEditPart> viewRes2ArtifactEPMap = new HashMap<Resource,ArtifactEditPart> ();
                        addFocusArtifacts(doc.getRDFDoc(), viewRes2ArtifactEPMap);
						addLinks(doc.getRDFDoc(), viewRes2ArtifactEPMap);
					}
				}
			});
		} catch (Exception e) {
		    logger.error("Unexpected exception", e);
		}

	}

	/**
	 * @see org.eclipse.gef.examples.flow.parts.ActivityPart#deactivate()
	 */
	@Override
    public void deactivate() {
		getViewer()
			.getEditDomain()
			.getCommandStack()
			.removeCommandStackListener(
			animationStackListener);
		super.deactivate();
	}
	
	@Override
	public void refresh() {
		for(ArtifactEditPart aep : getVisibleArtifactEditParts()) {
			aep.refresh();
		}
		for(ArtifactRelEditPart arep : getVisibleArtifactRelEditParts()) {
			arep.refresh();
		}
	}
	
	public void updateVisibility() {
		if (true) return;
		
		for(ArtifactEditPart aep : getVisibleArtifactEditParts()) {
			logger.error("Set opaque to false for: " + aep);
			aep.getFigure().setOpaque(false);
			//aep.getFigure().set
			aep.getContentPane().setOpaque(false);
			
			//if (aep instanceof MoreItemsEditPart) {
			//	((MoreItemsEditPart)aep).getMoreBtn().setOpaque(false);
			//}
		}
	}

    public boolean modelCreatable(Object model) {
        if (!(model instanceof Artifact)) 
            return false;
        else
            return this.artCreatable((Artifact) model);
    }

    public ImageDescriptor getIconDescriptor(NavAidsEditPart aep, Object relModel) {
        Artifact relArt = (Artifact) relModel;
        return ((MoreItemsEditPart)aep).getIconDescriptor(relArt, relArt.getType(aep.getRepo()));
    }
    
	public void exportImage(String file) {
		IFigure figure = getFigure();
		org.eclipse.draw2d.geometry.Rectangle r = figure.getBounds();
		Image image = null;
		GC gc = null;
		Graphics g = null;
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file, false);
			image = new Image(getViewer().getControl().getDisplay(), r.width,
					r.height);
			gc = new GC(image);
			g = new SWTGraphics(gc);
			g.translate(r.x * -1, r.y * -1);
			figure.paint(g);
			ImageLoader imageLoader = new ImageLoader();
			imageLoader.data = new ImageData[] { image.getImageData() };
			imageLoader.save(fos, guessFormat(file));
		}catch(Exception ex){
			logger.error("error saving file", ex);
		} finally {
			if (g != null) {
				g.dispose();
			}
			if (gc != null) {
				gc.dispose();
			}
			if (image != null) {
				image.dispose();
			}
			if (fos != null){
				try{
					fos.close();
				}catch(Exception e){}
			}
		}
	}

	public String getDefaultFileName() {
		List<ArtifactEditPart> parts = getSelectedArtifactEditParts();
		Artifact artifact = null;
		if (parts.size() > 0)
			artifact = parts.get(0).getArtifact();
		else if(getChildren().size()>0)
			artifact = (Artifact) ((EditPart) getChildren().get(0)).getModel();
		if(artifact == null)
			return "session";
		java.net.URI uri = java.net.URI.create(artifact.toString());
		return uri.getFragment();
	}

	private int guessFormat(String file) {
		file = file.toLowerCase();
		if (file.endsWith(".bmp"))
			return SWT.IMAGE_BMP;
		else if (file.endsWith(".jpg"))
			return SWT.IMAGE_JPEG;
		return SWT.IMAGE_PNG;
	}
	
    public void writeFile(IFile file) {
		try {
			final List<ArtifactRelEditPart> relEditParts = new ArrayList<ArtifactRelEditPart>();
			final List<ArtifactEditPart> editParts = new ArrayList<ArtifactEditPart>();
			final PipedInputStream in = new PipedInputStream();
			final PipedOutputStream out = new PipedOutputStream();
			in.connect(out);
			Thread t = new Thread() {
				@Override
                public void run() {
				    try {
                        writeFile(out,editParts,relEditParts);
                    } catch (IOException e) {
            			logger.error("Unexpected Error", e);
                    }
				}
			};
			t.start();
			if(file.exists())
				file.setContents(in, /*force*/true, /*keepHistory*/true, /*IProgressMonitor*/null);
			else
				file.create(in, true, null);
			
			//Add a statement to the repository indicating that this file is a .relo file,
			//and add a statement indicating each statement the file contains
			
			Resource res = ReloCore.eclipseResourceToRDFResource(getRepo(), file);
			getRepo().startTransaction();
			getRepo().addStatement(res, getRepo().rdfType, ReloCore.reloFile);
			getRepo().commitTransaction();

			for(ArtifactEditPart aep : editParts) {
				getRepo().startTransaction();
		    	getRepo().addStatement(res, ReloCore.contains, aep.getViewRes());
		    	getRepo().commitTransaction();
			}
			for(ArtifactRelEditPart arep : relEditParts) {
				getRepo().startTransaction();
		    	getRepo().addStatement(res, ReloCore.contains, arep.getViewRes());
		    	getRepo().commitTransaction();
			}
		} catch (IOException e) {
			logger.error("Unexpected Error", e);
		} catch (CoreException e) {
			logger.error("Unexpected Error", e);
		}		
	}

	private void writeFile(OutputStream out, List<ArtifactEditPart> editParts, List<ArtifactRelEditPart> relEditParts) throws IOException {
	    // let's do this in two passes, the first to get the namespaces
	    final RdfDocumentWriter rdfWriter = StoreUtil.getRDFWriter(out);
	    RdfDocumentWriter namespacesDeclarator = new RdfDocumentWriter() {
	        Set<String> namespaces = new HashSet<String> ();
	        private void declareReloNamespace(URI newURI) throws IOException {
	            String newNS = newURI.getNamespace();
	            if (namespaces.contains(newNS) || newNS.length()==0) return;
	            if (newNS.startsWith(ReloRdfRepository.reloRdfNamespace)) {
	                String prefixTrailer = newNS.substring(
	                        ReloRdfRepository.reloRdfNamespace.length(),
	                        newNS.length()-1);
	                setNamespace("relo-" + prefixTrailer, newNS);
	            }
	        }
            public void setNamespace(String prefix, String name) throws IOException {
	    	    namespaces.add(name);
                rdfWriter.setNamespace(prefix, name);
            }
            public void writeStatement(Resource subject, URI predicate, Value object) throws IOException {
	    	    if (subject instanceof URI) declareReloNamespace((URI)subject);
                declareReloNamespace(predicate);
	    	    if (object instanceof URI) declareReloNamespace((URI)object);
            }
            public void writeComment(String comment) throws IOException {}
            public void startDocument() throws IOException {}
            public void endDocument() throws IOException {}
	    };
	    namespacesDeclarator.setNamespace("rdf", RDF.NAMESPACE);
	    namespacesDeclarator.setNamespace("relo", ReloRdfRepository.reloRdfNamespace);

		writeView(namespacesDeclarator,editParts,relEditParts);
		writeView(rdfWriter,null,null);
		out.close();		
	}

	/**
	 * Called twice, the first pass with the declarator, the second pass for
	 *  the actual writing.
     * @param rdfWriter
	 * @param relEditParts 
	 * @param editParts 
     * @throws IOException
     */
    private void writeView(final RdfDocumentWriter rdfWriter, List<ArtifactEditPart> editParts, List<ArtifactRelEditPart> relEditParts) throws IOException {
        rdfWriter.startDocument();
		
		Resource rootRes = ReloCore.createReloURI("root");
		Literal classLoc = StoreUtil.createMemLiteral(StoreUtil.getClassLoc(bm.getBundleSymbolicName(), bm.getClass()));

        rdfWriter.writeStatement(rootRes, ReloEditor.browseModel, classLoc);		
	
		List<ArtifactEditPart> lst = getVisibleNonDerivedArtifactEditParts();
    	
		Iterator<ArtifactEditPart> lstIt = lst.iterator();
		while (lstIt.hasNext()) {
			ArtifactEditPart aep = (ArtifactEditPart) lstIt.next();
			Iterator aepRelsIt = aep.getSourceConnections().iterator();
			while (aepRelsIt.hasNext()) {
				ArtifactRelEditPart arep = (ArtifactRelEditPart) aepRelsIt.next();
				if(relEditParts!=null)
					relEditParts.add(arep);
				getRepo().startTransaction();
		        getRepo().addStatement(arep.getViewRes(), StoreUtil.createMemURI(RDF.TYPE), ReloCore.link);
		        getRepo().addStatement(arep.getViewRes(), ReloCore.model, arep.getArtifactRel().getType());
		        getRepo().addStatement(arep.getViewRes(), StoreUtil.createMemURI(RDF.SUBJECT), ((ArtifactEditPart)arep.getSource()).getViewRes());
		        getRepo().addStatement(arep.getViewRes(), StoreUtil.createMemURI(RDF.OBJECT), ((ArtifactEditPart)arep.getTarget()).getViewRes());
		        getRepo().commitTransaction();
		        ArtifactRelEditPart.writeRDF(arep, rdfWriter);
			}
			if(editParts!=null)
				editParts.add(aep);
			getRepo().startTransaction();
	    	getRepo().addStatement(aep.getViewRes(), StoreUtil.createMemURI(RDF.TYPE), ReloCore.node);
	        getRepo().addStatement(aep.getViewRes(), ReloCore.model, aep.getArtifact().elementRes);
	        getRepo().commitTransaction();
	        ArtifactEditPart.writeRDF(aep, rdfWriter);
	        
	        ReloRdfRepository fileStmts = ((StoreUnionRepository)bm.getRepo()).getCacheRepo();
	        StatementIterator iter =  StoreUtil.getDefaultStoreRepository().getStatements(aep.getArtifact().elementRes, null, null);
	        while(iter.hasNext()) {
	        	Statement stmt = iter.next();
	        	fileStmts.startTransaction();
	        	fileStmts.addStatement(aep.getArtifact().elementRes, stmt.getPredicate(), stmt.getObject());
	        	fileStmts.commitTransaction();
	        }
		}
		
		rdfWriter.endDocument();
    }

}
